package frans

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"log"
	"net/http"
	"reflect"
)

type Frans struct {
	*gin.Engine
	g *gin.RouterGroup

	//DB ORM
	db interface{}

	//多DB ORM  切换
	props []interface{}
}

//实例化
func Fighting() *Frans {

	gin.SetMode("debug")

	g := &Frans{Engine: gin.New()}
	//加载中间件
	g.Use(ErrorHandler())
	g.Use(gin.Logger(), gin.Recovery())
	return g
}

//中间件
func (this *Frans) Onion(f Onion) *Frans {

	this.Use(func(context *gin.Context) {
		err := f.OnRequest(context)
		if err != nil {
			context.AbortWithStatusJSON(http.StatusNotFound, gin.H{"error": err.Error()})
		} else {
			context.Next() // 继续往下走
		}
	})

	return this
}

//处理 控制器方法
func (this *Frans) Handle(httpMethod, relativePath string, handler interface{}) *Frans {

	//处理返回 String类型
	if h, ok := handler.(func(ctx *gin.Context) string); ok {
		this.g.Handle(httpMethod, relativePath, func(ctx *gin.Context) {
			ctx.String(http.StatusOK, h(ctx))
		})
	}

	//处理返回 Model类型
	if h, ok := handler.(func(ctx *gin.Context) Model); ok {
		this.g.Handle(httpMethod, relativePath, func(ctx *gin.Context) {
			ctx.JSON(http.StatusOK, h(ctx))
		})
	}

	//处理返回 Map类型
	if h, ok := handler.(func(ctx *gin.Context) gin.H); ok {
		this.g.Handle(httpMethod, relativePath, func(ctx *gin.Context) {
			ctx.JSON(http.StatusOK, h(ctx))
		})
	}

	return this
}

//控制器
func (this *Frans) Action(group string, classes ...IClass) *Frans {
	this.g = this.Group(group)
	for _, clazz := range classes {
		clazz.Route(this) // 遍历所有IController的具体实现， 并注册Route  这才是关键 !!!

		//TODO: 采用反射注入到控制器中
		vClass := reflect.ValueOf(clazz).Elem()

		//设置第一个字段为DB， 如果DB不是控制器的第一个内嵌字段，会报错！
		if vClass.NumField() > 0 {
			if this.db != nil {
				vClass.Field(0).Set(reflect.New(vClass.Field(0).Type().Elem()))
				vClass.Field(0).Elem().Set(reflect.ValueOf(this.db).Elem())
			}
		}

		//多字段设置
		/*for i := 0; i < vClass.NumField(); i++ {
			f := vClass.Field(i)
			if !f.IsNil() || f.Kind() != reflect.Ptr {
				continue
			}

			if p := this.DB(f.Type()); p != nil {
				f.Set(reflect.New(f.Type().Elem()))
				f.Elem().Set(reflect.ValueOf(p).Elem())
			}
		}*/

	}

	return this
}

//开始战斗吧 骚年 ！！！
func (this *Frans) Start() {
	config := InitConfig()

	log.Fatal(this.Run(fmt.Sprintf(":%d", config.Server.Port)))
}

//设置数据库链接对象
func (this *Frans) DB(db interface{}) *Frans {
	this.db = db
	return this
}

//设置数据库链接对象 切换
/*func (this *Frans) Beans(beans ...interface{}) *Frans {
	this.props = append(this.props, beans...)
	return this
}*/
